package com.vf.cloud.pass.common.factory;

import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.jfinal.kit.StrKit;
import com.vf.cloud.pass.common.domain.biz.TerminalGpu;
import com.vf.cloud.pass.common.util.R;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class GPUFactory {

	private static volatile GPUFactory INSYANCE;

	public static GPUFactory getInstance() {
		if (null == INSYANCE) {
			synchronized (GPUFactory.class) {
				if (null == INSYANCE) {
					INSYANCE = new GPUFactory();
				}
			}
		}
		return INSYANCE;
	}

	private ConcurrentHashMap<String, String> GPU_USED_RESOURCE = new ConcurrentHashMap<String, String>();
	private ConcurrentHashMap<String, String> GPU_FREE_RESOURCE = new ConcurrentHashMap<String, String>();

	private ConcurrentHashMap<String, Date> TIME_OUT = new ConcurrentHashMap<String, Date>();

	public void check() {
		if (TIME_OUT != null || TIME_OUT.size() <= 0) {
			TIME_OUT.clear();
			return;
		}
		log.info(String.format("GPU_WAIT_RESOURCE :%s", TIME_OUT.size()));
		Iterator<String> it = TIME_OUT.keySet().iterator();
		while (it.hasNext()) {
			String gpuindex = it.next();
			if (!GPU_USED_RESOURCE.containsKey(gpuindex)) {
				if (TIME_OUT.containsKey(gpuindex)) {
					if (new Date(System.currentTimeMillis()).getTime() > TIME_OUT.get(gpuindex).getTime()) {
						TIME_OUT.remove(gpuindex);
						GPU_FREE_RESOURCE.put(gpuindex, "");
						log.info(String.format("GPU is Timeout,Kill:%s", gpuindex));
					}
				} else {
					TIME_OUT.put(gpuindex, getLaterTime());
					log.info(String.format("GPU add To Timeout :%s", gpuindex));
				}
			} else {
				if (TIME_OUT.containsKey(gpuindex)) {
					TIME_OUT.remove(gpuindex);
					log.info(String.format("GPU remove Timeout :%s", gpuindex));
				}
			}
		}
	}

	public void removeTimeout(String EIO) {
		TIME_OUT.remove(EIO);
	}

	private Date getLaterTime() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MINUTE, 1);
		return cal.getTime();
	}

	public void use(String gpu, String src) {
		if (!StrKit.isBlank(src)) {
			GPU_USED_RESOURCE.put(gpu, src);
		}
	}

	public R<String> apply(String sid,Map<String,String> rendering) {
		if (GPU_FREE_RESOURCE.size() <= 0) {
			return R.failed("渲染资源已达上线.");
		}
		String renderingKey = "";
		Iterator<String> it = GPU_FREE_RESOURCE.keySet().iterator();
		while (it.hasNext()) {
			String key = it.next();
			if(rendering.containsKey(key.substring(0, key.indexOf("|")).trim())) {
				renderingKey=key;
			}
			break;
		}
		if (StrKit.isBlank(renderingKey)) {
			return R.failed("渲染资源已达上线.");
		}
		GPU_FREE_RESOURCE.remove(renderingKey);
		TIME_OUT.put(renderingKey,  getLaterTime());
		return R.ok(renderingKey);
	}

	/**
	 * 初始化节点资源
	 * 
	 * @param terminalId
	 */
	public void init(String terminalId) {
		List<TerminalGpu> list = TerminalGpu.dao
				.find("select * from " + TerminalGpu.TABLE_NAME + " where terminal_id=?", terminalId);
		for (TerminalGpu g : list) {
			for (int i = 0; i < g.getGpuLimit(); i++) {
				if (!GPU_USED_RESOURCE.containsKey(String.format("%s|%s|%s", terminalId, g.getGpuIndex(), i))) {
					GPU_FREE_RESOURCE.put(String.format("%s|%s|%s", terminalId, g.getGpuIndex(), i), "");
				}
			}
		}
	}

	/**
	 * 失去连接清除节点资源
	 * 
	 * @param terminalId
	 */
	public void disconnected(String terminalId) {
		List<TerminalGpu> list = TerminalGpu.dao
				.find("select * from " + TerminalGpu.TABLE_NAME + " where terminal_id=?", terminalId);
		for (TerminalGpu g : list) {
			for (int i = 0; i < g.getGpuLimit(); i++) {
				GPU_USED_RESOURCE.remove(String.format("%s|%s|%s", terminalId, g.getGpuIndex(), i));
				GPU_FREE_RESOURCE.remove(String.format("%s|%s|%s", terminalId, g.getGpuIndex(), i));
			}
		}

	}

	public void release(String key) {
		if (GPU_USED_RESOURCE.containsKey(key)) {
			GPU_USED_RESOURCE.remove(key);
		}
		GPU_FREE_RESOURCE.put(key, "");
	}

}
